package com.lagou.rpc.consumer.zk;

import lombok.Data;
import org.I0Itec.zkclient.ZkClient;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


@Data
public class ZkUtil {

    private List<String> serverList = new ArrayList<>();

    private ZkClient zkClient;

    private final String parentPath = "/rpc-server";

    public ZkUtil() {
        zkClient = new ZkClient("127.0.0.1:2181");
    }


    public void subscribeChildChanges() {
        设置定时， 每五秒检测一次
        ScheduledExecutorService executor = new ScheduledThreadPoolExecutor(1);
        executor.scheduleAtFixedRate(() -> {
            List<String> children = zkClient.getChildren(parentPath);
            for (String child : children) {
                String ip = child.split("-")[0];
                String port = child.split("-")[1];
                Object o = zkClient.readData(parentPath + "/" + child);
                if (o == null) {
                    continue;
                }
                int time = Integer.parseInt(o.toString());
                //如果耗时超过5秒，则认为该节点失效，从ZK节点上删除
                if (time > 5000) {
                    zkClient.delete(parentPath + "/" + ip + "-" + port);
                }
                //将该节点数据修改为耗时时间
                zkClient.writeData(parentPath + "/" + ip + "-" + port, time + "");
                System.out.println("最后一次请求" + ip + ":" + port + " 花费了 " + time + "毫秒");
            }
        }, 5, 5, TimeUnit.SECONDS);

        //节点监听
        zkClient.subscribeChildChanges(parentPath, (s, list) -> {
            System.out.println(parentPath + "的子节点列表发生了变化,变化后的子节点列表为" + list);
            // 重新获取服务器节点信息
            serverList = list;
        });

    }

    public void updateData(String server,long time){
        zkClient.writeData(parentPath + "/" + server, time + "");

    }

    public List<String> getNode() {
        serverList = zkClient.getChildren(parentPath);
        // 判断节点中存储的连接时间，取时间短的，如果时间一致则轮询
        List<String> children = zkClient.getChildren(parentPath);
        int chooseTime = Integer.MAX_VALUE;
        //获取节点数据(服务器响应时间)
        String ip = null;
        int port = 0;
        //获取响应时间最小的那台服务器进行调用
        for (String child : children) {
            Object o = zkClient.readData(parentPath + "/" + child);
            if (o == null) {
                o = 0;
            }
            int time = Integer.parseInt(o.toString());
            if (time < chooseTime) {
                chooseTime = time;
                ip = child.split("-")[0];
                port = Integer.parseInt(child.split("-")[1]);
            }
        }
        //如果ZK服务器上还未保存服务端的响应时间信息，或者时间是0
        if (chooseTime == 0 || ip == null) {
            return serverList;
        }
        serverList.clear();
        serverList.add(ip + "-" + port);
        return serverList;
    }


}
